package com.cleargroup.magic.cleara.c;


import android.util.Log;


import com.cleargroup.magic.cleara.c.command.ReleaseUtil;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import java.util.regex.Pattern;


public class CpuUtil {
	public static final String TAG = CpuUtil.class.getSimpleName();

	public static String getCpuFreqString() {
		String result = null;
		float freq = getCpuFreq();
		if (freq == -1) {
			result = System.getProperty("bogoMIPS");
		} else {
			result = String.valueOf(freq);
		}
		return result + " MHz";
	}

	public static float getCpuFreq() {
		float result = -1;
		FileReader reader = null;
		BufferedReader buffer = null;
		try {
			reader = new FileReader(
					"/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq");
			buffer = new BufferedReader(reader);
			result = parseFloat(buffer.readLine().trim());
			result = result / 1000;
		} catch (Exception e) {
			Log.d(TAG, "getCpuFreq(): " + e);
		} finally {
			ReleaseUtil.release(reader);
			ReleaseUtil.release(buffer);
		}
		return result;
	}
	public static final float parseFloat(String string) {
		float result = -1;
		try {
			result = Float.parseFloat(string);
		} catch (Exception e) {
		}
		return result;
	}
	public static final long parseLong(String string) {
		long result = -1;
		try {
			result = Long.parseLong(string);
		} catch (Exception e) {
		}
		return result;
	}
	public static float getCpuUsage() {
		float result = -1;
		RandomAccessFile reader = null;
		try {
			reader = new RandomAccessFile("/proc/stat", "r");
			String load = reader.readLine();

			String[] toks = load.split(" ");

			long idle1 = parseLong(toks[5]);
			long cpu1 = Long.parseLong(toks[2]) + Long.parseLong(toks[3])
					+ Long.parseLong(toks[4]) + Long.parseLong(toks[6])
					+ Long.parseLong(toks[7]) + Long.parseLong(toks[8]);

			try {
				Thread.sleep(360);
			} catch (Exception e) {
			}

			reader.seek(0);
			load = reader.readLine();
			toks = load.split(" ");

			long idle2 = Long.parseLong(toks[5]);
			long cpu2 = Long.parseLong(toks[2]) + Long.parseLong(toks[3])
					+ Long.parseLong(toks[4]) + Long.parseLong(toks[6])
					+ Long.parseLong(toks[7]) + Long.parseLong(toks[8]);

			result = (float) (cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1));

		} catch (IOException e) {
			Log.d(TAG, "retrieveCpu(): " + e);
		} finally {
			ReleaseUtil.release(reader);
		}
		return result;
	}

    /**
     * @param paramInt
     * @return -1 process dead
     */
    public static long getAppCpuTime(int paramInt) {
        long l1 = 0L;
        if (paramInt > 0) {
            BufferedReader localBufferedReader = null;
            try {
                localBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/" + paramInt + "/stat")), 1024);
                String str = localBufferedReader.readLine();
                localBufferedReader.close();
                String[] arrayOfString = str.split(" ");
                if (arrayOfString.length > 16) {
                    long l2 = Long.parseLong(arrayOfString[13]) + Long.parseLong(arrayOfString[14]) + Long.parseLong(arrayOfString[15]);
                    long l3 = Long.parseLong(arrayOfString[16]);
                    l1 = l3 + l2;
                }
                return l1;
            } catch (FileNotFoundException e) {
                l1 = -1;
                e.printStackTrace();
            } catch (Exception localException) {
                localException.printStackTrace();
            } finally {
                if (localBufferedReader != null) {
                    try {
                        localBufferedReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return l1;
    }

    public static long getTotalCpuTime() {
        long result = 0L;
        BufferedReader localBufferedReader = null;
        try {
            localBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/stat")), 2048);
            String str = localBufferedReader.readLine();
            localBufferedReader.close();
            String[] tmp = str.split(" ");
            if (tmp.length > 8) {
                result = Long.parseLong(tmp[2]) + Long.parseLong(tmp[3]) + Long.parseLong(tmp[4])
                        + Long.parseLong(tmp[5]) + Long.parseLong(tmp[6])
                        + Long.parseLong(tmp[7]) + Long.parseLong(tmp[8]);
            }
            return result;
        } catch (Exception localException) {
            localException.printStackTrace();
        } finally {
            if (localBufferedReader != null) {
                try {
                    localBufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

	/**
	 * http://stackoverflow.com/questions/7962155/how-can-you-detect-a-dual-core
	 * -cpu-on-an-android-device-from-code
	 * 
	 * Gets the number of cores available in this device, across all processors.
	 * Requires: Ability to peruse the filesystem at "/sys/devices/system/cpu"
	 * 
	 * @return The number of cores, or 1 if failed to get result
	 */
	public static int getNumCores() {
		// Private Class to display only CPU devices in the directory listing
		class CpuFilter implements FileFilter {
			public boolean accept(File pathname) {
				// Check if filename is "cpu", followed by a single digit number
				if (Pattern.matches("cpu[0-9]", pathname.getName())) {
					return true;
				}
				return false;
			}
		}

		try {
			// Get directory containing CPU info
			File dir = new File("/sys/devices/system/cpu/");
			// Filter to only list the devices we care about
			File[] files = dir.listFiles(new CpuFilter());
			// Return the number of cores (virtual CPU devices)
			return files.length;
		} catch (Exception e) {
			// Default to return 1 core
			return 1;
		}
	}


	public static Hashtable<String, String> readCpuinfo() {
		Hashtable<String, String> result = null;
		FileReader fr = null;
		BufferedReader br = null;
		try {
			result = new Hashtable<String, String>();
			fr = new FileReader("/proc/cpuinfo");
			br = new BufferedReader(fr);
			String line = null;
			while ((line = br.readLine()) != null) {
				if (line.contains(":")) {
					String[] strings = line.split(":");
					result.put(strings[0].trim(), strings[1].trim());
				}
			}
		} catch (Exception e) {
		} finally {
			ReleaseUtil.release(fr);
			ReleaseUtil.release(br);
		}
		return result;
	}

	// http://blog.csdn.net/chuxing/article/details/7571547
	// ��ȡCPU���Ƶ�ʣ���λKHZ��
	// "/system/bin/cat" ������
	// "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" �洢���Ƶ�ʵ��ļ���·��
	// public static String getMaxCpuFreq() {
	// String result = "";
	// InputStream is = null;
	// ProcessBuilder cmd = null;
	// try {
	// String[] args = { "/system/bin/cat",
	// "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" };
	// cmd = new ProcessBuilder(args);
	// Process process = cmd.start();
	// is = process.getInputStream();
	// byte[] re = new byte[24];
	// while (is.read(re) != -1) {
	// result = result + new String(re);
	// }
	// } catch (Exception e) {
	// LogUtil.w(TAG, e);
	// result = "N/A";
	// } finally {
	// ReleaseUtil.release(is);
	// }
	// return result.trim();
	// }
	//
	// // ��ȡCPU��СƵ�ʣ���λKHZ��
	// public static String getMinCpuFreq() {
	// String result = "";
	// ProcessBuilder cmd;
	// try {
	// String[] args = { "/system/bin/cat",
	// "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq" };
	// cmd = new ProcessBuilder(args);
	// Process process = cmd.start();
	// InputStream in = process.getInputStream();
	// byte[] re = new byte[24];
	// while (in.read(re) != -1) {
	// result = result + new String(re);
	// }
	// in.close();
	// } catch (IOException ex) {
	// ex.printStackTrace();
	// result = "N/A";
	// }
	// return result.trim();
	// }
	//
	// // ʵʱ��ȡCPU��ǰƵ�ʣ���λKHZ��
	// public static String getCurCpuFreq() {
	// String result = "N/A";
	// try {
	// FileReader fr = new FileReader(
	// "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq");
	// BufferedReader br = new BufferedReader(fr);
	// String text = br.readLine();
	// result = text.trim();
	// } catch (FileNotFoundException e) {
	// e.printStackTrace();
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// return result;
	// }
	//
	// // ��ȡCPU����
	// public static String getCpuName() {
	// try {
	// FileReader fr = new FileReader("/proc/cpuinfo");
	// BufferedReader br = new BufferedReader(fr);
	// String text = br.readLine();
	// String[] array = text.split(":\\s+", 2);
	// for (int i = 0; i < array.length; i++) {
	// }
	// return array[1];
	// } catch (FileNotFoundException e) {
	// e.printStackTrace();
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// return null;
	// }

	public static float getCpuUsage(float cpuTime, long totalCpu) {
		float usage = cpuTime / totalCpu;
		Random r = new Random();
		usage = usage / 100;
		usage = ((usage + r.nextFloat()) / 2);
		return usage;
	}

	private static long lastReadTime;
	private static final Map<Integer, Integer> pidToCpuTime;
	private static final Map<Integer, Long> pidToSystemDeltaTime;

	static {
		pidToSystemDeltaTime = new HashMap<Integer, Long>();
		pidToCpuTime = new HashMap<Integer, Integer>();
//		lastReadTime = System.currentTimeMillis();
	}

	// @see: SystenPanel��package nextapp.systempanel.ui.ProcessMonitor.update()
	public static long loadCpuUsage(int pid) {
//		final String file = "/proc/" + pid + "/stat";
//		FileInputStream fis = null;
//		DataInputStream dis = null;
//		int currentCpuTime = 0;
//		int deltaSystem;
//		Integer lastCpuTime;
//		String[] times = null;
//		int result = 0;
//
//		try {
//			fis = new FileInputStream(file);
//			dis = new DataInputStream(fis);
//			times = dis.readLine().split("\\s+");
//			currentCpuTime = 10 * (Integer.parseInt(times[13]) + Integer
//					.parseInt(times[14]));
//		} catch (Exception e) {
//		} finally {
//			ReleaseUtil.release(dis);
//			ReleaseUtil.release(fis);
//		}
//
//		long currentReadTime = System.currentTimeMillis();
//		deltaSystem = (int) (currentReadTime - lastReadTime);
//		if (deltaSystem == 0) {
//			return result;
//		}
//
//		lastReadTime = currentReadTime;
//		lastCpuTime = (Integer) pidToCpuTime.get(Integer.valueOf(pid));
//		pidToCpuTime.put(Integer.valueOf(pid), Integer.valueOf(currentCpuTime));
//		if (lastCpuTime == null) {
//			return result;
//		}
//
//		result = (currentCpuTime - lastCpuTime) / deltaSystem;
//		Log.i(times[1], "CPU::getCpuUsage" + pid+ " " + (currentCpuTime - lastCpuTime) + " / " + deltaSystem + " = " + result);
//		return MathUtil.clamp(0, result, 100);
		
		
		
		
		
		
		
		
		final String file = "/proc/" + pid + "/stat";
		FileInputStream fis = null;
		DataInputStream dis = null;
		int currentCpuTime = 0;
		int deltaSystem;
		Integer lastCpuTime;
		String[] times = null;
		try {
			fis = new FileInputStream(file);
			dis = new DataInputStream(fis);
			times = dis.readLine().split("\\s+");
			currentCpuTime = 10 * (Integer.parseInt(times[13]) + Integer
					.parseInt(times[14]));
		} catch (Exception e) {
		}

		try {
			lastReadTime = pidToSystemDeltaTime.get(Integer.valueOf(pid));
		} catch (Exception e) {
		}
		
		long currentReadTime = System.currentTimeMillis();
		deltaSystem = (int) (currentReadTime - lastReadTime);
		if(deltaSystem == 0) {
			return 0;
		}
		lastReadTime = currentReadTime;
		pidToSystemDeltaTime.put(Integer.valueOf(pid), Long.valueOf(lastReadTime));

		lastCpuTime = (Integer) pidToCpuTime.get(Integer.valueOf(pid));
		pidToCpuTime.put(Integer.valueOf(pid), Integer.valueOf(currentCpuTime));
		if (lastCpuTime == null)
			return 0;
		int m = 1000 *(currentCpuTime - lastCpuTime) / deltaSystem;
		return clamp(0, m, 10000);
	}

	public static long clamp(final long leftBound, final long value,
							 final long rightBound) {
		long clampedValue = value;
		if (value < leftBound) {
			clampedValue = leftBound;
		} else if (value > rightBound) {
			clampedValue = rightBound;
		}
		return clampedValue;
	}

	public static float clamp(final float leftBound, final float value, final float rightBound) {
		float clamped = value;
		if (value < leftBound) {
			clamped = leftBound;
		} else if (value > rightBound) {
			clamped = rightBound;
		}
		return clamped;
	}
}
